package com.onpositive.mediawiki.serializing;

import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.IOException;
import java.util.Iterator;

import javax.imageio.IIOImage;
import javax.imageio.ImageIO;
import javax.imageio.ImageWriteParam;
import javax.imageio.ImageWriter;
import javax.imageio.stream.MemoryCacheImageOutputStream;

import com.onpositive.data.serializer.readers.DefaultReaderFactory;
import com.onpositive.data.serializer.writers.ByteArrayWriter;
import com.onpositive.image.factories.AbstractImageFitter;
import com.onpositive.image.factories.ImageFitterFactory;

public class PictureWriter extends AbstractMediaWikiWriter<String> {
	
	public static final Class<?>[] CONSTRUCTOR_ARGUMENTS = { String.class, float.class, int.class, int.class } ; 
	public static final String KEY_IMAGE_TYPE = "image-type" ;
	public static final String KEY_COMPRESSION_QUALITY = "compression-quality" ;
	public static final String KEY_IMAGE_WIDTH = "image-width" ;
	public static final String KEY_IMAGE_HEIGHT = "image-height" ;
	
	private static final int INT_SIZE = 4;
	
	private int width, height ;
	private float quality ;
	private String imageType ;
	
	private ByteArrayOutputStream byteStorage ;
	private MemoryCacheImageOutputStream streamLocal ;
	
	private String fitterId ;
	private AbstractImageFitter imageFitter ;
	
	private ImageWriter defaultWriter ;
	private ImageWriteParam iwp ;
	
	private int nonNullImageCount = 0 ;
	
	ByteArrayWriter byteArrayWriter = new ByteArrayWriter() ;
	
	public PictureWriter() {
		super( String.class );
	}
	
	public PictureWriter( String imageType, float quality, int width, int height )
	{
		super( String.class );
		this.imageType = imageType ;
		this.quality = quality ;
		this.width = width ;
		this.height = height ;
		
		this.fitterId = ImageFitterFactory.ID_BASIC_IMAGE_FITTER ;
		this.imageFitter = ImageFitterFactory.getInstance().getFitter( this.fitterId ) ;
		
		this.byteStorage = new ByteArrayOutputStream() ;
		
		this.defaultWriter  = createWriter();		
		this.iwp = createQualityParam(this.defaultWriter);		
	}

	@Override
	protected void append(String value)
	{
		BufferedImage bufImg = null ;
		byte[] dose = null ;
		
		if( value != null && value.length() != 0 )
		{
			try {
				bufImg = ImageIO.read( new File( value ) ) ;
			} catch ( Exception e) {
				e.printStackTrace();
				bufImg = null ;
				dose = null ;
			}
		}
		
		if( bufImg != null )
		{
			try{
				byteStorage.reset() ;
				this.streamLocal = new MemoryCacheImageOutputStream( this.byteStorage ) ;
				this.defaultWriter.setOutput( streamLocal );
				
				BufferedImage imgTmp = imageFitter.fitImage( bufImg, this.width, this.height ) ;
				IIOImage image = new IIOImage( imgTmp, null, null);
						
				defaultWriter.write( null, image, iwp ) ;								
				nonNullImageCount++ ;
				
				dose = byteStorage.toByteArray() ;						
			}
			catch( IOException e ){
				e.printStackTrace() ;
				dose = null ;
			}
		}
		byteArrayWriter.append( dose ) ;		
		//doTest() ;		
	}	

	@Override
	public void serialize( DataOutputStream stream ) throws IOException
	{
		int totalSizeInBytes = byteArrayWriter.getSize();
		
		System.out.print( "Image store size: " ) ;		
		System.out.print( totalSizeInBytes ) ;
		System.out.print( "\n" ) ;
		System.out.print( "Images count: " ) ;		
		System.out.print( nonNullImageCount ) ;
		System.out.print( "\n" ) ;
		
		byteArrayWriter.serialize( stream ) ;		
	}

	private ImageWriteParam createQualityParam(ImageWriter defaultWriter) {
		ImageWriteParam iwp = defaultWriter.getDefaultWriteParam();
		iwp.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
		iwp.setCompressionQuality( this.quality );
		return iwp;
	}

	private ImageWriter createWriter() {
		Iterator<ImageWriter> iter = ImageIO.getImageWritersByFormatName( this.imageType ) ;
		ImageWriter defaultWriter = iter.next() ;
		return defaultWriter;
	}
	
	@Override
	protected int getID()
	{
		return DefaultReaderFactory.RW_ID_BYTE_ARRAY ;		
	}

	public int getWidth() {
		return width;
	}

	public void setWidth(int width) {
		this.width = width;
	}

	public int getHeight() {
		return height;
	}

	public void setHeight(int height) {
		this.height = height;
	}

	public float getQuality() {
		return quality;
	}

	public void setQuality(float quality) {
		this.quality = quality;
	}

	public String getImageType() {
		return imageType;
	}

	public void setImageType(String imageType) {
		this.imageType = imageType;
	}

//	private void doTest() {		
//		
//		String path = "C:\\wikistorage\\!testImage\\" ;
//		int start = offsets.get( offsets.size() - 2 ) ;
//		int end   = offsets.get( offsets.size() - 1 ) ;
//		
//		int length = end - start ;
//		if ( length == 0 )
//			return ;
//		
//		byte[] totalArr = this.streamMain.toByteArray() ;
//		byte[] currentArr = new byte[length] ;
//		System.arraycopy( totalArr, start, currentArr, 0, length ) ;
//		
//		String hash = ( "" + this.hashCode() ).substring( 0, 5 ) ;
//		
//		try {
//			FileOutputStream fs = new FileOutputStream( new File(path + "_" + hash + "_" + this.nonNullImageCount +".jpg") ) ;
//			fs.write( currentArr ) ;
//			fs.close() ;
//		} catch (FileNotFoundException e) {
//			e.printStackTrace();
//		} catch (IOException e) {
//			e.printStackTrace();
//		}
//	}
	
}
